﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace PlcUI_test
{
    public partial class theWelderUI : Form
    {
        protected TheWelders theWelders;  // 储存的是焊机当前状态，目标状态需要其他字段

        /// <summary>
        /// 数据表，用于显示焊机状态
        /// </summary>
        protected DataTable dataTable;

        /// <summary>
        /// 显示的键值
        /// </summary>
        protected Dictionary<string, string> dictionaryTitles;

        /// <summary>
        /// 焊机当前状态
        /// </summary>
        protected List<TheWelderBase> theWeldersOutput;

        /// <summary>
        /// 焊机目标状态
        /// </summary>
        protected List<TheWelderBase> theWeldersInput;

        /// <summary>
        /// 选中的焊机索引
        /// </summary>
        protected List<bool> theSelectedWeldersIndex;

        protected MqttClientWithJson mqttClientWithJson;  // 通信类



        // 自定义控件的引用列表，方便集体调用
        protected List<MyControls.WelderStatusShow> welderStatusShows; // 焊机状态显示控件

        protected List<MyControls.FourRadioButton> fourRadioButtons;

        protected List<MyControls.ButtonCheck> buttonChecks;

        protected List<MyControls.ThreeRadioButton> threeRadioButtons;

        protected List<MyControls.WelderMode> welderModes;

        protected List<MyControls.InputBoxButton> inputBoxButtons;

        protected List<Panel> panels;

        // 整体来说，这个UI里面必须存有数据，theWelders是UI这个类的字段
        // 在构造器里面初始化这个字段
        // 前端：TheWelderUI，后端：TheWelders。后端只有状态，前端需要显示状态和输入状态


        /// <summary>
        /// 焊机UI的构造器，初始化时会调用
        /// </summary>
        public theWelderUI()
        {
            InitializeComponent();
            this.DoubleBuffered = true;
            // this.WindowState = FormWindowState.Maximized; // 窗口最大化
            /*
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new theWelderUI());     //摁下一个按键触发焊机检测的UI
             */
            this.SuspendLayout();
            InitAllThings();
            this.ResumeLayout();
            // this.SizeChanged += TheWelderUI_SizeChanged;
        }

        private void InitAllThings()
        {
            // TODO: 初始化所有东西，包括焊机选择框，PLC状态，TCLManager等
            this.theWelders = new TheWelders();
            InitializeWeldersCheckBox();
            InitializeTheWeldersInputandOutput();
            // 初始化状态展示控件的地址，用哈希表更方便的存储数据
            this.welderStatusShows = new List<MyControls.WelderStatusShow>();
            this.fourRadioButtons = new List<MyControls.FourRadioButton>();
            this.buttonChecks = new List<MyControls.ButtonCheck>();
            this.threeRadioButtons = new List<MyControls.ThreeRadioButton>();
            this.welderModes = new List<MyControls.WelderMode>();
            this.inputBoxButtons = new List<MyControls.InputBoxButton>();
            this.panels = new List<Panel>();

            // 通信状态初始化
            mqttClientWithJson = new MqttClientWithJson();
            mqttClientWithJson.JsonQueuesNotEmpty += JsonQueuesHandle;


            FindWelderStatusShow(this);   // 递归找到列表中有用的控件，所有的控件动态数组初始化必须在这个之前完成
            foreach (Panel panel in this.panels)
            {
                if (panel.Name.ToString().IndexOf("inputPanel") >= 0)
                {
                    panel.Enabled = false;
                }
            }
            InitializeStatusShowPanel();
            InitializeEvent();
            InitializeDataGridView();
        }

        /// <summary>
        /// 添加新的控件事件处理逻辑
        /// </summary>
        private void InitializeEvent()
        {
            this.statusPanelButtons2.Button1Click += new System.EventHandler(this.PlcTimerTickerChange);
            this.statusPanelButtons2.Button2Click += new System.EventHandler(this.PlcTimerTickerChangeFalse);
            this.statusPanelButtons2.Button4Click += new System.EventHandler(this.statusPanelButtons2_Button4Click);
        }






        /// <summary>
        /// 初始化焊机状态显示控件，获取对应控件
        /// </summary>
        // 这个地方实际上就用到了多叉树，用递归遍历
        private void FindWelderStatusShow(Control parentControl)
        {
            foreach (Control control in parentControl.Controls)
            {
                // 添加引用到列表中，便于直接调用


                if (control is MyControls.FourRadioButton)
                    fourRadioButtons.Add((MyControls.FourRadioButton)control);

                if (control is MyControls.ButtonCheck)
                    buttonChecks.Add((MyControls.ButtonCheck)control);

                if (control is MyControls.ThreeRadioButton)
                    threeRadioButtons.Add((MyControls.ThreeRadioButton)control);

                if (control is MyControls.WelderMode)
                    welderModes.Add((MyControls.WelderMode)control);

                if (control is MyControls.InputBoxButton)
                    inputBoxButtons.Add((MyControls.InputBoxButton)control);

                if (control is Panel panel)
                    panels.Add((Panel)control);

                if (control.Controls.Count > 0)
                {
                    FindWelderStatusShow(control);
                }
            }
        }



        private void TheWelderUI_SizeChanged(object sender, EventArgs e)
        {
            SuspendAllLayouts(this);
            // 在这里进行其他操作


            ResumeAllLayouts(this);
        }

        private void SuspendAllLayouts(Control parent)
        {
            parent.SuspendLayout();
            foreach (Control child in parent.Controls)
            {
                SuspendAllLayouts(child);
            }
        }

        private void ResumeAllLayouts(Control parent)
        {
            parent.ResumeLayout();
            foreach (Control child in parent.Controls)
            {
                ResumeAllLayouts(child);
            }
        }



        #region 焊机选择模块


        /// <summary>
        /// 将面板按钮初始化为默认状态
        /// </summary>
        private void ButtonsInitialize()
        {
            foreach (var buttonControl in fourRadioButtons)
            {
                buttonControl.Inilialize();
            }
            foreach (var buttonControl in threeRadioButtons)
            {
                buttonControl.Initialize();
            }
            foreach (var buttonControl in buttonChecks)
            {
                buttonControl.Initialize();
            }
            foreach (var buttonControl in welderModes)
            {
                buttonControl.Initialize();
            }
            foreach (var buttonControl in inputBoxButtons)
            {
                buttonControl.Initialize();
            }

        }

        /// <summary>
        /// 在选中更新之后，将按钮初始化为默认状态
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WelderscheckedListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ButtonsInitialize();
        }

        /// <summary>
        /// 焊机选择框多选初始化
        /// </summary>\
        public void InitializeWeldersCheckBox()
        {
            WelderscheckedListBox.Items.Clear();
            for (int i = 1; i <= theWelders.GetWelderCount(); i++)
            {
                WelderscheckedListBox.Items.Add("焊机" + i);
            }
        }


        /// <summary>
        /// 初始化焊机的目标状态，初始化选中焊机的索引
        /// </summary>
        public void InitializeTheWeldersInputandOutput()
        {
            int welderCount = theWelders.GetWelderCount();
            this.theWeldersOutput = new List<TheWelderBase>(welderCount);
            this.theWeldersInput = new List<TheWelderBase>(welderCount);
            this.theSelectedWeldersIndex = new List<bool>(welderCount);
            for (int i = 0; i < welderCount; i++)
            {
                this.theWeldersInput.Add(new TheWelderBase());
                this.theWeldersOutput.Add(new TheWelderBase());
                this.theSelectedWeldersIndex.Add(false);
            }
        }

        /// <summary>
        /// 索引初始化，都为不选中状态
        /// </summary>
        public void ClearSelectedWeldersIndex()
        {
            for (int i = 0; i < this.theSelectedWeldersIndex.Count; i++)
            {
                this.theSelectedWeldersIndex[i] = false;
            }
        }


        /// <summary>
        /// 清除焊机的三个按钮
        /// </summary>
        public void ClearSelectedWeldersCheckBox()
        {
            SelectAllCheckBox.Checked = false;
            SeparateCheckBox.Checked = false;
            ConcentrateCheckBox.Checked = false;
        }
        /// <summary>
        /// 清除焊机选择框的勾选状态
        /// </summary>
        public void ClearSelectedWeldersCheckListBox()
        {
            for (int i = 0; i < WelderscheckedListBox.Items.Count; i++)
            {
                WelderscheckedListBox.SetItemChecked(i, false);
            }
        }

        /// <summary>
        /// 焊机勾选框的勾选事件，每次勾选都会触发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WelderscheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
        {

            ClearSelectedWeldersIndex();  // 清除选中焊机索引
            ButtonsInitialize(); // 清除按钮，虽然会触发写入事件，但是没有索引是没办法写入的

            // 使用委托，在主线程中执行
            // 每次勾选都更新选择的东西
            this.BeginInvoke((MethodInvoker)delegate
            {

                foreach (var item in WelderscheckedListBox.CheckedItems)
                {
                    //Console.WriteLine("选中" + item.ToString());   // 输出选中的内容
                    int index = WelderscheckedListBox.Items.IndexOf(item);
                    this.theSelectedWeldersIndex[index] = true;
                }
                theWelders.PLCWriteSelect(this.theSelectedWeldersIndex);
                // 同步对选中进行更新
                // 这个部分不知道有没有问题，还需要我来进行测试

                //foreach (var item in this.theSelectedWeldersIndex)
                //{ Console.WriteLine(item); }  // 测试代码
                SelectAllCheckBoxStatus();  // 判定是否全选了


            });
        }

        /// <summary>
        /// 选中所有焊机
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SelectAllCheckBox_CheckedChanged(object sender, EventArgs e)
        {

            SeparateCheckBox.Checked = false;  // 改变剩下俩按钮的状态
            ConcentrateCheckBox.Checked = false;

            if (SelectAllCheckBox.CheckState == CheckState.Checked)
            {
                for (int i = 0; i < theWelders.GetWelderCount(); i++)
                {
                    this.theSelectedWeldersIndex[i] = true;
                    WelderscheckedListBox.SetItemChecked(i, true);
                }

                SelectAllCheckBox.CheckState = CheckState.Checked;
                // 这行代码因为选择框单击一下就会触发，但是不打勾，无奈之举
            }

            SelectAllCheckBoxStatus();


        }
        /// <summary>
        /// 分离焊机选中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SeparateCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            SelectAllCheckBox.Checked = false;  // 改变剩下俩按钮的状态
            ConcentrateCheckBox.Checked = false;

            if (SeparateCheckBox.CheckState == CheckState.Checked)
            {
                ClearSelectedWeldersIndex();  // 清除索引
                ClearSelectedWeldersCheckListBox();  // 清除选择框
                for (int i = theWelders.GetConcentratedWelderCount(); i < theWelders.GetWelderCount(); i++)
                {
                    this.theSelectedWeldersIndex[i] = true;
                    WelderscheckedListBox.SetItemChecked(i, true);
                }
                // 从24之后在进行选中
            }
        }
        /// <summary>
        /// 集中焊机选中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ConcentrateCheckBox_CheckedChanged(object sender, EventArgs e)
        {

            SelectAllCheckBox.Checked = false;  // 改变剩下俩按钮的状态
            SeparateCheckBox.Checked = false;
            if (ConcentrateCheckBox.CheckState == CheckState.Checked)
            {
                ClearSelectedWeldersIndex();  // 清除索引
                ClearSelectedWeldersCheckListBox();  // 清除选择框
                for (int i = 0; i < theWelders.GetConcentratedWelderCount(); i++)
                {
                    this.theSelectedWeldersIndex[i] = true;
                    WelderscheckedListBox.SetItemChecked(i, true);
                }
            }
        }
        /// <summary>
        /// 清除所有的勾选状态
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearCheckBoxsButton_Click(object sender, EventArgs e)
        {
            ClearSelectedWeldersCheckBox();
            ClearSelectedWeldersCheckListBox();
            ClearSelectedWeldersIndex();  // 清除索引
        }

        /// <summary>
        /// 全选状态检测
        /// </summary>
        private void SelectAllCheckBoxStatus()
        {
            if (this.theSelectedWeldersIndex.Contains(false))
            {
                SelectAllCheckBox.CheckState = CheckState.Unchecked;
            }
            else
            {
                SelectAllCheckBox.CheckState = CheckState.Checked;
            }
        }

        #endregion



        /// <summary>
        /// 输入的数字转化
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public int TextToInt(string text)
        {
            // TODO: 检查输入是否为数字
            return 0;
        }





        #region 选中焊机数值写入

        // 这一部分需要对选中模块进行大改，选中了才能写入
        /// <summary>
        /// 焊机数值写入模块
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Typename"> 需要写入的类型名称 </param>
        /// <param name="value"> 写入的具体值 </param>
        private void InputValues<T>(string Typename, T value)
        {
            StringInputPLC<T>(Typename, value);  // 测试先用着。等回去的时候重构的时候再改
            for (int i = 0; i < theWelders.GetWelderCount(); i++)
            {
                var oldValue = theWeldersInput[i].GetType().GetProperty(Typename).GetValue(theWeldersInput[i], null);
                if (this.theSelectedWeldersIndex[i])
                {
                    // StringInputPLC<T>(Typename, value, i);
                    theWeldersInput[i].GetType().GetProperty(Typename).SetValue(theWeldersInput[i], value, null);

                    // TestWelderInputFunction(valueName : Typename, theWelder: theWeldersInput[i], index : i);
                }
                // Console.WriteLine(Typename + theWeldersInput[i].GetType().GetProperty(Typename).GetValue(theWeldersInput[i], null));



                //// 数据写入成功了的话
                //if (this.theSelectedWeldersIndex.Contains(true) && oldValue != theWeldersInput[i].GetType().GetProperty(Typename).GetValue(theWeldersInput[i], null))
                //{
                //    PlcInputStatus("未向PLC写入数据更改", System.Drawing.SystemColors.Control);
                //}
            }
        }




        /// <summary>
        /// 通过变量再PLC中的名称直接写入数值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Typename"></param>
        /// <param name="value"></param>
        /// <param name="index"></param>
        private void StringInputPLC<T>(string Typename, T value)
        {
            for (int i = 0; i < theSelectedWeldersIndex.Count; i++)
            {
                if (this.theSelectedWeldersIndex[i] && theWelders.AdsClient.IsConnected)
                {
                    string valuePath = "GVL_Welders.Welders[" + i + "]." + Typename;
                    try
                    {
                        theWelders.AdsClient.WriteSymbol(valuePath, value, false);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("写入数据失败，请检查PLC连接是否正常！\n" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }


        /// <summary>
        /// 向PLC中是否写入更改的数据标签
        /// </summary>
        /// <param name="text">显示的文本</param>
        /// <param name="color">标签背景颜色</param>
        private void PlcInputStatus(string text, Color color)
        {
            PlcInputSuccess.Text = text;
            PlcInputSuccess.BackColor = color;
        }


        #endregion


        /// 这部分代码还需要再完善，因为目前显示哪些数据还没有说



        /// <summary>
        /// 显示当前页焊机状态数据，实际上调用了currentPage参数
        /// </summary>
        /// <param name="theWelderList"></param>
        /// <param name="welderIndex"></param>
        public void ShowWelderStatusDataGrid(List<TheWelderBase> theWelderList)
        {
            
        }

        private void ColunmsChanged(TheWelderBase theWelder, int currentCol)
        {

        }

        /// <summary>
        /// 初始化状态展示面板，使用数据表格形式
        /// </summary>
        private void InitializeDataGridView()
        {
            // TODO: 初始化数据表格，使用DataTable
            // dataGridView1.ColumnHeadersVisible = false; // 隐藏列头

            dictionaryInitialize();
            InitializeDataGridViewWithDataTable();

        }

        /// <summary>
        /// 键值对初始化，来自于定义好的数据类
        /// </summary>
        private void dictionaryInitialize()
        {
            // 到时候把这一部分改成配置文件
            dictionaryTitles = new Dictionary<string, string>
            {
                { "ID", "焊机编号" },
                {"H_R_I_CommunicationStatus", "通讯状态" },
                {"H_R_I_ISWeldingMachineReady","焊机准备状态" },
                {"H_R_I_ArcIgnitionSuccessful","引弧状态" },
                {"H_W_D_BaseCurrent","基值电流" },
                {"H_W_D_PeakCurrent","峰值电流" },
                {"H_R_D_ActualWeldingCurrent","实际焊接电流" },
                {"H_R_D_ActualWeldingVoltage","实际焊接电压" },
                {"H_W_B_DutyCycle","占空比" },
                {"H_W_B_PulseFrequency","脉冲频率" },
                {"S_R_D_WireFeedingSpeed","送丝机速度" },
                {"R_R_D_HotWirecurrent","实际热丝电流" },
                {"R_W_B_HotWireCurrent","目标热丝电流" },
                {"H_W_Q_ISHighfrequency","是否高频" },
                {"H_W_Q_WeldingGunMode","冷却模式" }
            };
        }

        /// <summary>
        /// 初始化数据表格，使用DataTable
        /// </summary>
        private void InitializeDataGridViewWithDataTable()
        {
            dataTable = new DataTable();
            // 添加列
            foreach (var kvp in dictionaryTitles)
            {
                // 添加列，列名为字典的值（中文列名），列类型为 string
                dataTable.Columns.Add(kvp.Value, typeof(string));
            }

            // 添加行空数据
            for (int row = 0; row < columnCount; row++)
            {
                DataRow dr = dataTable.NewRow();
                for (int col = 0; col < dataTable.Columns.Count; col++)
                {
                    dr[col] = $"行{row + 1},列{col + 1}"; // 填充示例数据
                }
                dataTable.Rows.Add(dr);
            }

            

            // 设置默认字体大小与位置
            dataGridView1.ColumnHeadersDefaultCellStyle.Font = new Font("Arial", 12, FontStyle.Bold);
            dataGridView1.DefaultCellStyle.Font = new Font("Arial", 10);

            dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
            dataGridView1.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;


            // 绑定 DataTable 到 DataGridView
            dataGridView1.DataSource = dataTable;
            // 设置列宽自适应
            dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
            // 调整行高，确保表格填满控件
            AdjustRowHeights();

            // 禁用列排序功能
            foreach (DataGridViewColumn column in dataGridView1.Columns)
            {
                column.SortMode = DataGridViewColumnSortMode.NotSortable;
            }
        }
        private void AdjustRowHeights()
        {
            // 等待 DataGridView 加载完毕
            dataGridView1.RowPostPaint += (s, e) =>
            {
                // 计算每行的高度，确保行高填满整个控件
                int totalHeight = dataGridView1.ClientSize.Height;
                int rowCount = dataGridView1.Rows.Count;

                if (rowCount > 0)
                {
                    int rowHeight = totalHeight / rowCount;
                    foreach (DataGridViewRow row in dataGridView1.Rows)
                    {
                        row.Height = rowHeight;
                    }
                }
            };
        }


        #region 状态轮播实现


        /// <summary>
        /// 状态显示页面当前页数
        /// </summary>
        private int currentPage;

        /// <summary>
        /// 是否轮播，默认为轮播模式
        /// </summary>
        private bool showStatusRunning;

        private System.Threading.CancellationTokenSource cancellationTokenSource;

        /// <summary>
        /// 状态显示列数
        /// </summary>
        private int columnCount = 0;

        /// <summary>
        /// 焊机状态总数
        /// </summary>
        private int welderCount;

        /// <summary>
        /// 总页数
        /// </summary>
        private int totalPage;

        /// <summary>
        /// 停留时间， 单位毫秒
        /// </summary>
        private System.Windows.Forms.Timer refreshTimer;

        /// <summary>
        /// 初始化状态显示控件
        /// </summary>
        private void InitializeStatusShowPanel()
        {
            currentPage = 0;
            showStatusRunning = false;
            cancellationTokenSource = new System.Threading.CancellationTokenSource();

            columnCount = 10;    // 展示列数
            welderCount = theWelders.GetWelderCount();    // 焊机总数
            totalPage = (welderCount + columnCount - 1) / columnCount;   // 总页数

            // 初始化定时器
            refreshTimer = new System.Windows.Forms.Timer();
            refreshTimer.Interval = 5000;    // 每一页刷新事件间隔
            refreshTimer.Tick += StartStatusRunning;


            // 初始化按钮事件
            this.statusPanelButtons1.Button1Click += statusPanelButtons1_Button1Click;
            this.statusPanelButtons1.Button2Click += statusPanelButtons1_Button2Click;
            this.statusPanelButtons1.Button3Click += statusPanelButtons1_Button3Click;
            this.statusPanelButtons1.Button4Click += statusPanelButtons1_Button4Click;
            // this.statusPanelButtons1.Button5Click += statusPanelButtons1_Button5Click;


        }



        /// <summary>
        /// 使用定时器轮播焊机状态
        /// </summary>
        private void StartStatusRunning(object sender, EventArgs e)
        {
            DisplayPage();
            currentPage++;
        }


        /// <summary>
        /// 检查当前页面是否有效
        /// </summary>
        private void CheckCurrentPage()
        {
            if (currentPage < 0)
            {
                currentPage = totalPage - 1;
            }
            if (currentPage >= totalPage)
            {
                currentPage = 0;
            }
        }

        /// <summary>
        /// 检查是否需要启动定时器
        /// </summary>
        private void CheckShowStatusRunning()
        {
            if (showStatusRunning)
            {
                statusPanelButtons1.RadioButton1Checked = true;
                refreshTimer.Start();
            }
            else
            {
                statusPanelButtons1.RadioButton2Checked = true;   // 直接写成true才会有显示
                refreshTimer.Stop();
            }
        }

        /// <summary>
        /// 显示当前页的焊机状态
        /// </summary>
        private void DisplayPage()
        {
            CheckCurrentPage();

            int startIndex = currentPage * columnCount;

            // 这个地方可以用并行，后续再改
            
            DisplayTable();
        }

        /// <summary>
        /// 展示当前页焊机列表的状态
        /// </summary>
        private void DisplayTable()
        {
            CheckCurrentPage();

            int startIndex = currentPage * columnCount;
            int i = 0;
            foreach(DataRow row in dataTable.Rows)
            {
                foreach(string str in dictionaryTitles.Keys)
                {
                    string temp1 = dictionaryTitles[str];

                    // 查找对应的 PropertyInfo
                    System.Reflection.PropertyInfo propertyInfo = Array.Find(TheWelderBase.baseProperties, p => p.Name == str);
                    if (propertyInfo != null)
                    {
                        // 获取对应属性的值并赋给 DataRow
                        Console.WriteLine(propertyInfo.GetValue(theWeldersOutput[startIndex + i]));
                        var value = propertyInfo.GetValue(theWeldersOutput[startIndex + i]);
                        row[dictionaryTitles[str]] = value?.ToString(); // 用 value?.ToString() 防止 null 引发异常
                    }
                    else if(str == "ID")
                    {
                        string tmp = theWeldersOutput[startIndex + i].WelderName + (startIndex + i + 1).ToString();
                        row[dictionaryTitles[str]] = tmp;
                    }
                }
                i++;
            }
        }

        /// <summary>
        /// 轮播焊机状态
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void statusPanelButtons1_Button1Click(object sender, EventArgs e)
        {
            DisplayPage();  // 先展示一次，后面就自动轮播
            showStatusRunning = true;
            CheckShowStatusRunning();
            // Console.WriteLine("statusPanelButtons1_Button1Click");
        }

        /// <summary>
        /// 暂停轮播
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void statusPanelButtons1_Button2Click(object sender, EventArgs e)
        {
            showStatusRunning = false;
            CheckShowStatusRunning();
            // Console.WriteLine("statusPanelButtons1_Button2Click");
        }
        /// <summary>
        /// 上一页
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void statusPanelButtons1_Button3Click(object sender, EventArgs e)
        {
            // Console.WriteLine("statusPanelButtons1_Button3Click");
            statusPanelButtons1_Button2Click(sender, e);
            currentPage--;
            DisplayPage();
        }
        /// <summary>
        /// 下一页
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void statusPanelButtons1_Button4Click(object sender, EventArgs e)
        {
            // Console.WriteLine("statusPanelButtons1_Button4Click");
            statusPanelButtons1_Button2Click(sender, e);
            currentPage++;
            DisplayPage();
        }

        /// <summary>
        /// 更新显示数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void statusPanelButtons1_Button5Click(object sender, EventArgs e)
        {
            // Console.WriteLine("statusPanelButtons1_Button5Click");
            showStatusRunning = false;
            theWeldersOutput = this.theWelders.GetWelderInformation();
            DisplayPage();
        }

        #endregion


        /// <summary>
        /// 连接PLC
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PlcStartConnected(object sender, EventArgs e)
        {
            if (statusPanelButtons2.RadioButton1Checked)
            {
                try
                {
                    theWelders.Connect();
                    statusPanelButtons2.RadioButton2Checked = false;
                    if (theWelders.AdsClient != null)
                    {
                        MessageBox.Show("连接成功");
                        plcIsConnected.Text = "已连接PLC";
                        plcIsConnected.BackColor = Color.FromArgb(192, 255, 192);
                        PanelLock(true);

                        // 连接成功就开启循环读数
                        // this.statusPanelButtons2.button1Click(this, e);
                        // 通过check事件来触发两个事件
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    PlcConnectedFailed();
                }
            }
        }

        /// <summary>
        /// 断开PLC连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PlcFinishedConnected(object sender, EventArgs e)
        {

            //TimerTicker = false;  // 无论是否开启定时读取，只要断开PLC连接，都要断掉定时读取
            //ChangeTimerLabelUI("读取停止", System.Drawing.SystemColors.Control); // 循环读数取消
            PlcConnectedFailed();
            try
            {
                theWelders.Disconnect();
            }
            catch (Exception ex)
            {
                MessageBoxShow("未连接plc，无需断开连接" + ex.Message);
            }

        }

        /// <summary>
        /// PLC连接失败，对相关控件进行处理
        /// </summary>
        private void PlcConnectedFailed()
        {
            statusPanelButtons2.RadioButton2Checked = true;
            plcIsConnected.Text = "未连接PLC";
            plcIsConnected.BackColor = System.Drawing.SystemColors.Control;
            PanelLock(false);

        }

        /// <summary>
        /// 写入面板是否可用
        /// </summary>
        /// <param name="value">为true则是可用</param>
        private void PanelLock(bool value)
        {
            foreach (Panel panel in this.panels)
            {
                if (panel.Name.ToString().IndexOf("inputPanel") >= 0)
                {
                    panel.Enabled = value;
                }
            }
        }


        #region 定时读取PLC数据


        /// <summary>
        /// 定时读取PLC数据开关标志位
        /// </summary>
        private bool TimerTicker = false;

        /// <summary>
        /// 开始定时读取PLC数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// // designer1653行 将此事件绑定到button1上，每次连接plc成功就触发
        private async void PlcTimerTickerChange(object sender, EventArgs e)
        {
            TimerTicker = true;  // 只有启动的时候才是真实的值

            try
            {
                // 开启循环读取的时候必须监测一下是否客户端已经创立并连接
                if (theWelders.AdsClient != null && theWelders.AdsClient.IsConnected)
                {
                    cancellationTokenSource = new CancellationTokenSource();
                    // 浅绿色Color.FromArgb(192, 255, 192); 

                    ChangeTimerLabelUI("开始读取", Color.FromArgb(192, 255, 192));

                    await StartDataReading(cancellationTokenSource.Token);
                }
                else
                {
                    if (cancellationTokenSource != null)
                    {
                        cancellationTokenSource.Cancel();
                        cancellationTokenSource.Dispose();
                    }
                    // ChangeTimerLabelUI("读取停止", System.Drawing.SystemColors.Control);
                    this.statusPanelButtons2.button2Click(true);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("请检查PLC是否连接，" + ex.Message);
            }
        }

        /// <summary>
        /// 关闭定时读取PLC数据事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PlcTimerTickerChangeFalse(object sender, EventArgs e)
        {
            TimerTicker = false;
            ChangeTimerLabelUI("读取停止", System.Drawing.SystemColors.Control);
        }

        private void ChangeTimerLabelUI(string text, Color color)
        {
            Timerlabel.Text = text;
            Timerlabel.BackColor = color;
        }
        /// <summary>
        /// 异步读取数据
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task StartDataReading(CancellationToken cancellationToken)
        {
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    if (!TimerTicker)
                    {
                        throw new Exception("中断数据读取");
                    }
                    await Task.Run(() =>
                    {
                        try
                        {
                            theWelders.ReadValues();
                            for (int i = 0; i < GlobalVariables.WelderNum; i++)
                            {
                                theWeldersOutput[i].UpdateStructureValues(theWelders.AllPlcWelderStatus.Axis[i]);
                            }
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                            TimerTicker = false;  // 关闭定时读取，防止出错
                        }
                    });

                    // 更新UI
                    UpdateUI();   // 这段代码负责了UI的更新，后面可以去掉这部分，用两个不同的异步进行更新
                    // 定时
                    await Task.Delay(TimeSpan.FromMilliseconds(300), cancellationToken);

                    // 这里的异步操作被取消后，会抛出TaskCanceledException异常，需要进行异常处理。
                }

            }
            catch (TaskCanceledException)
            {
                MessageBox.Show("循环读取数据取消");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                this.statusPanelButtons2.button2Click(true);
            }
        }

        private void UpdateUI()
        {
            if (InvokeRequired)
            {
                Invoke(new Action(UpdateUI));
            }
            else
            {
                DisplayPage();
            }
        }




        #endregion





        /// <summary>
        /// 整体向PLC中写入更改的数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PlcValuesInput(object sender, EventArgs e)
        {
            if (theWelders.AdsClient != null)
            {
                try
                {
                    // theWelders.WriteValues(theWeldersInput);


                    PlcInputStatus("成功向PLC中写入数据", Color.FromArgb(192, 255, 192));
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else
            {
                MessageBox.Show("PLC未连接");
            }
        }


        #region PLC数据单个写入事件

        /// <summary>
        /// 基值电流数值写入  H_W_D_BaseCurrent属性
        /// </summary>
        /// <param name="value"></param>
        private void BackgroundCurrent_ButtonClicked(double value)
        {
            // this.theWeldersInput[0].BaseCurrent = (ushort)value; // 直接使用显式转换
            // Console.WriteLine("BaseCurrent: " + this.theWeldersInput[10].BaseCurrent);
            // TODO: 需要添加筛选函数
            InputValues<ushort>(BaseCurrent.ValueName, (ushort)value);
        }

        /// <summary>
        /// 峰值电流数值写入  H_W_D_PeakCurrent属性
        /// </summary>
        /// <param name="value"></param>
        private void PeakCurrent_ButtonClicked(double value)
        {
            InputValues<ushort>(PeakCurrent.ValueName, (ushort)value);
        }
        /// <summary>
        /// 占空比数值写入  H_W_B_DutyCycle属性
        /// </summary>
        /// <param name="value"></param>
        private void DutyCycle_ButtonClicked(double value)
        {
            InputValues<byte>(DutyCycle.ValueName, (byte)value);
        }
        /// <summary>
        /// 热丝机电流频率写入  R_W_B_HotWireFrequency属性
        /// </summary>
        /// <param name="value"></param>
        private void HotWireFrequency_ButtonClicked(double value)
        {
            InputValues<byte>(HotWireFrequency.ValueName, (byte)value);
        }
        /// <summary>
        /// 脉冲频率数值写入  H_W_B_PulseFrequency属性
        /// </summary>
        /// <param name="value">2-200对应0.2-20.0hz</param>
        private void PulseFrequency_ButtonClicked(double value)
        {
            InputValues<float>(PulseFrequency.ValueName, (float)(value));  // 注意这一部分的10.0
        }
        /// <summary>
        /// 目标热丝机电流写入 R_W_B_HotWireCurrent
        /// </summary>
        /// <param name="value"></param>
        private void HotWireCurrent_ButtonClicked(double value)
        {
            InputValues<byte>(HotWireCurrent.ValueName, (byte)value);
        }

        /// <summary>
        /// 送丝机送丝速度写入 S_W_B_Wirefeedingspeed
        /// </summary>
        /// <param name="value">0-70对应0-7m/min</param>
        private void Wirefeedingspeed_ButtonClicked(double value)
        {
            InputValues<float>(Wirefeedingspeed.ValueName, (float)(value));
        }






        /// <summary>
        /// 热丝机电流模式选择事件
        /// </summary>
        /// <param name="sender">触发的控件</param>
        /// <param name="e">对应的bool值</param>
        private void HotWireWorkMode_ButtonCheckedChanged(object sender, bool e)
        {
            MyControls.ButtonCheck buttonCheck = sender as MyControls.ButtonCheck;
            InputValues<bool>(buttonCheck.ValueName, e);
        }

        /// <summary>
        /// 起弧触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Astart_ButtonCheckedChanged(object sender, bool e)
        {
            MyControls.ButtonCheck buttonCheck = sender as MyControls.ButtonCheck;
            InputValues<bool>(buttonCheck.ValueName, e);
        }

        /// <summary>
        /// 气检触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GasCheck_ButtonCheckedChanged(object sender, bool e)
        {
            MyControls.ButtonCheck buttonCheck = sender as MyControls.ButtonCheck;
            InputValues<bool>(buttonCheck.ValueName, e);
        }
        /// <summary>
        /// 热丝机启动触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HotWirePower_ButtonCheckedChanged(object sender, bool e)
        {
            MyControls.ButtonCheck buttonCheck = sender as MyControls.ButtonCheck;
            InputValues<bool>(buttonCheck.ValueName, e);
        }



        /// <summary>
        /// 设置送丝机状态
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SongSiMode_ButtonCheckedChanged(object sender, bool e)
        {
            MyControls.ThreeRadioButton songSiButton = sender as MyControls.ThreeRadioButton;
            // songSiButton的ValueName不为空且不为空字符串（定义了空字符串就是停止功能）
            if (!string.IsNullOrEmpty(songSiButton.ValueName))
            {
                // InputValues<bool>(songSiButton.ValueName, e);
                if (songSiButton.Button1Checked)
                {
                    // 两个属性只能有一个亮
                    InputValues<bool>(songSiButton.ValueName1, e);
                    InputValues<bool>(songSiButton.ValueName2, !e);

                }
                else if (songSiButton.Button2Checked)
                {
                    InputValues<bool>(songSiButton.ValueName2, e);
                    InputValues<bool>(songSiButton.ValueName1, !e);
                }

            }
            else
            {
                InputValues<bool>(songSiButton.ValueName1, !e);
                InputValues<bool>(songSiButton.ValueName2, !e);
            }
        }

        /// <summary>
        /// 焊接模式选择事件
        /// </summary>
        /// <param name="sender">触发的控件</param>
        /// <param name="e"></param>
        private void WorkModel_ButtonCheckedChanged(object sender, bool e)
        {
            InputValues<short>(WorkModel.VariableName, WorkModel.WorkModel);  // 写入short参数，判断状态
        }

        private void OperationMode_ButtonCheckChanged(object sender, short e)
        {
            InputValues<short>(OperationMode.ValueName, e);
        }

        private void OpenWelder_ButtonCheckedChanged(object sender, bool e)
        {
            if (!e)
            {
                // 如果是焊机关闭，那就把起弧也关掉，必须重启才能起弧
                InputValues<bool>("H_W_Q_Start", e);
            }
            InputValues<bool>(OpenWelder.ValueName, e);
        }

        private void ISHighfrequency_ButtonCheckedChanged(object sender, bool e)
        {
            InputValues<bool>(ISHighfrequency.ValueName, e);
        }

        private void WeldingGunMode_ButtonCheckedChanged(object sender, bool e)
        {
            InputValues<bool>(WeldingGunMode.ValueName, e);
        }

        private void GivenCurrent_ButtonClicked(double obj)
        {
            InputValues<ushort>(GivenCurrent.ValueName, (ushort)obj);
        }

        private void PreAirTime_ButtonClicked(double obj)
        {
            InputValues<float>(PreAirTime.ValueName, (float)(obj));
        }

        private void DelayAirTime_ButtonClicked(double obj)
        {
            InputValues<float>(DelayAirTime.ValueName, (float)(obj));
        }

        private void ClimbingTime_ButtonClicked(double obj)
        {
            InputValues<float>(ClimbingTime.ValueName, (float)(obj));
        }

        private void SDecayTime_ButtonClicked(double obj)
        {
            InputValues<float>(SDecayTime.ValueName, (float)(obj));
        }

        private void ArcingCurrent_ButtonClicked(double obj)
        {
            InputValues<ushort>(ArcingCurrent.ValueName, (ushort)obj);
        }

        private void ArcCurrent_ButtonClicked(double obj)
        {
            InputValues<ushort>(ArcCurrent.ValueName, (ushort)obj);
        }

        private void CommunicationFrequency_ButtonClicked(double obj)
        {
            InputValues<byte>(CommunicationFrequency.ValueName, (byte)obj);
        }

        private void CleaningRatio_ButtonClicked(double obj)
        {
            InputValues<byte>(CleaningRatio.ValueName, (byte)obj);
        }

        private void ACOffset_ButtonClicked(double obj)
        {
            InputValues<byte>(ACOffset.ValueName, (byte)obj);
        }

        private void ArcInitiationDelayWireFeedingTime_ButtonClicked(double obj)
        {
            InputValues<float>(ArcInitiationDelayWireFeedingTime.ValueName, (float)(obj));
        }

        private void ArcExtinguishingDelayWireFeedingTime_ButtonClicked(double obj)
        {
            InputValues<float>(ArcExtinguishingDelayWireFeedingTime.ValueName, (float)(obj));
        }

        private void ArcExtinguishingAndRetractionlength_ButtonClicked(double obj)
        {
            InputValues<byte>(ArcExtinguishingAndRetractionlength.ValueName, (byte)obj);
        }

        private void JoggingWireFeedingSpeed_ButtonClicked(double obj)
        {
            InputValues<float>(JoggingWireFeedingSpeed.ValueName, (float)(obj));
        }

        private void SlowWireFeedingSpeed_ButtonClicked(double obj)
        {
            InputValues<float>(SlowWireFeedingSpeed.ValueName, (float)(obj));
        }


        #endregion

        #region 预定流程设置
        /// <summary>
        /// 预定流程队列
        /// </summary>
        private Queue<JsonCommunication> taskQueue = new Queue<JsonCommunication>();


        private void QueueInilize()
        {
            taskQueue.Enqueue(new JsonCommunication(BaseCurrent.ValueName, (ushort)50, 5000));
            taskQueue.Enqueue(new JsonCommunication(DutyCycle.ValueName, (byte)50, 0));
            taskQueue.Enqueue(new JsonCommunication(BaseCurrent.ValueName, (ushort)20, 5000));
            taskQueue.Enqueue(new JsonCommunication(DutyCycle.ValueName, (byte)20, 0));
            taskQueue.Enqueue(new JsonCommunication(BaseCurrent.ValueName, (ushort)10, 5000));
            taskQueue.Enqueue(new JsonCommunication(DutyCycle.ValueName, (byte)10, 0));
            // taskQueue.Enqueue(new JsonCommunication("S_W_Q_WirePullingJog", true, 0));
            // 到时候看怎么用这一部分的东西，如果object就成那我也不用改了
        }


        /// <summary>
        /// 预定流程的触发机制，需要手动写一些东西
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void statusPanelButtons2_Button4Click(object sender, EventArgs e)
        {
            QueueInilize();  // 测试用队列代码
            if (theWelders.AdsClient.IsConnected)
            {
                // 创建任务列表，每个任务包含延迟时间和具体的泛型参数
                while (taskQueue.Count > 0)
                {
                    var oneQueneTask = taskQueue.Dequeue();
                    await RunTaskWithDelay(oneQueneTask.valueName, oneQueneTask.value, oneQueneTask.delayMilliseconds);
                }

                MessageBoxShow("所有任务完成！");
            }
            else
            {
                MessageBoxShow("请先连接PLC！");
            }
        }

        /// <summary>
        /// 异步向PLC中写入数值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name">PLC变量名称</param>
        /// <param name="value">对应的值，请指定类型转换</param>
        /// <param name="delayMilliseconds">异步等待时间，单位ms</param>
        /// <returns></returns>
        private async Task RunTaskWithDelay<T>(string name, T value, int delayMilliseconds)
        {
            await Task.Delay(delayMilliseconds); // 等待延迟时间
            InputValues<T>(name, value); // 执行任务，实际使用的东西
            // InputValuesTest<T>(name, value);  // 代码测试
            // HandleTask(name, value);             // 执行任务
        }

        /// <summary>
        /// 泛型方法：处理输入值，测试
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <param name="value"></param>
        private void InputValuesTest<T>(string name, T value)
        {
            Console.WriteLine($"Name: {name}, Value: {value}");
        }
        // 泛型方法：处理任务逻辑
        private void HandleTask<T>(string name, T value)
        {
            MessageBox.Show($"任务完成：{name}, 值：{value}, 类型：{typeof(T).Name}");
        }


        /// <summary>
        /// 异步显示消息框但是不阻止主线程任务执行
        /// </summary>
        /// <param name="message"></param>
        private async void MessageBoxShow(string message)
        {
            await Task.Run(() => MessageBox.Show(message));
        }
        #endregion



        #region 通讯使用代码

        /// <summary>
        /// 处理Json队列消息任务，将值写入到下位机中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void JsonQueuesHandle(object sender, EventArgs e)
        {
            while (mqttClientWithJson.JsonQueues.Count > 0)
            {
                var oneQueneTask = mqttClientWithJson.JsonQueues.Dequeue();

                while (oneQueneTask.Count > 0)
                {
                    ID_SelectAndValueInput(oneQueneTask);
                }
            }
        }

        /// <summary>
        /// 处理Json队列消息任务，将值写入到下位机中，分辨对应变量名是什么，消息类是mqttClientWithJson
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        private void ID_SelectAndValueInput(Queue<KeyValuePair<string, Newtonsoft.Json.Linq.JToken>> oneQueneTask)
        {
            int index = 0;
            while (oneQueneTask.Count > 0)
            {
                var oneTask = oneQueneTask.Dequeue();  
                if (oneTask.Key == MqttClientWithJson.SelectID_Key)  // 用于分辨选中的焊机对应的key
                {
                    try
                    {
                        index = Convert.ToInt32(oneTask.Value) - 1 ;
                    }
                    catch(Exception)
                    {
                        Console.WriteLine("json字符串转化成焊机选中索引int失败");
                    }
                }
                else
                {
                    // 索引错误检查，防止报错，默认改0
                    if (index < 0 || index > theWelders.GetWelderCount() - 1)
                        index = 0;

                    if ( theWelders.AdsClient.IsConnected)
                    {

                        // string valuePath = "GVL_Welders.Welders[" + index + "]." + oneTask.Key;
                        string valuePath = "GVL_Welders.Welders[" + index + "]." + ((Newtonsoft.Json.Linq.JArray)mqttClientWithJson.config[oneTask.Key])[0].ToString();
                        string valueType = ((Newtonsoft.Json.Linq.JArray)mqttClientWithJson.config[oneTask.Key])[1].ToString();
                        object value = ConvertToType(oneTask.Value, valueType);
                        try
                        {
                            theWelders.AdsClient.WriteSymbol(valuePath, value, false);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("写入数据失败，请检查PLC连接是否正常！\n" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                }
            }
        }


        /// <summary>
        /// 类型转化函数，通过类型字典来获取对应的类型并转换数据
        /// </summary>
        /// <param name="token"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        private object ConvertToType(Newtonsoft.Json.Linq.JToken token, string typeName)
        {
            try
            {
                // 使用 TypeMapping 字典来进行类型转换
                Type type = MqttClientWithJson.TypeMapping[typeName];
                TypeCode typeCode = Type.GetTypeCode(type);

                return Convert.ChangeType(token, typeCode);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Exception: 转换类型时发生错误. 错误信息: {ex.Message}");
                return null;
            }
        }



        /// <summary>
        /// 通过变量再PLC中的名称直接写入数值，不经过选中的index列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Typename"></param>
        /// <param name="value"></param>
        private void InputValues2<T>(string Typename, T value)
        {
            try
            {
                theWelders.AdsClient.WriteSymbol(Typename, value, false);
            }
            catch (Exception ex)
            {
                MessageBox.Show("写入数据失败，请检查PLC连接是否正常！\n" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion
    }
}

